package utils.parser;

import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import kb.DescriptionLogicsKB;
//import kb.DescriptionLogicsKB;
import kb.KBStat;

import utils.exception.SyntaxParsingException;
import entities.assertion.Assertion;
import entities.axiom.Axiom;
import entities.axiom.InclusionAxiom;
import entities.concept.AtomicConcept;
import entities.concept.Concept;
import entities.concept.ExistsConcept;
import entities.concept.NotConcept;
import entities.concept.OrConcept;
import entities.concept.UniversalConcept;
import static option.KBVocabulary.*;

public class Parser {

	private Parser() {
	}

	// deal with axioms and convert concepts to GCIs for TBox
	public static Axiom parseAxioms(LinkedList<String> tokens, DescriptionLogicsKB kb)
			throws SyntaxParsingException {
		if (tokens.peek() == null) {
			System.out.println("Empty list of tokens, please check!");
			throw new SyntaxParsingException();
		}
		String first = tokens.getFirst();
		// test on the tokens
		if (!first.equals(LEFTDEL)) {
			System.out.println("Outer brackets expected.");
			throw new SyntaxParsingException();
		} else {
			tokens.remove();
			// remove the last symbol which is ")"
			String test = tokens.removeLast();
			assert test.equals(RIGHTDEL);
		}
		// axiom? remove brackets and parse
		Axiom ax = null;
		if (tokens.peek().equals(IMPLIES)) {
			tokens.remove();
			ax = Creator.createInclusionAxiom(tokens, kb);
		} else if (tokens.peek().equals(EQAXIOM)) {
			// equivalent axiom
			tokens.remove();
			ax = Creator.createEqAxiom(tokens, kb);
		} else if (tokens.peek().equals(ROLEAXIOM)) {
			// role inclusion axiom
			tokens.remove();
			ax = Creator.createRoleIncAxiom(tokens, kb);
		} else if (tokens.peek().equals(ROLE_INV)) {
			// role inverse axiom
			tokens.remove();
			ax = Creator.createRoleInverseAxiom(tokens, kb);
		} else if (tokens.peek().equals(ROLE_TRANS)) {
			// role transitive axiom
			tokens.remove();
			ax = Creator.createRoleTransitiveAxiom(tokens, kb);
		} else if (tokens.peek().equals(FEAT_DOM)) {
			// role inclusion axiom
			tokens.remove();
			ax = Creator.createFeatureDomAxiom(tokens, kb);
		}
		else {
			// other cases: into GCI
			throw new SyntaxParsingException("Error when parsing axioms :"+tokens);
//			ax = new InclusionAxiom(
//					entities.vocabulary.KBVocabulary.CONCEPT_TOP, conParser(
//							tokens, stat));
		}
		// if (debug) System.out.println(Renderer.renderAxiom(ax));
		return ax;
	}

	public static LinkedList<String> getListOfTokensFromTokenizer(String line) {
		Tokenizer t = new Tokenizer(line);
		LinkedList<String> list = new LinkedList<String>();
		while (t.hasNextToken()) {
			String st = null;
			try {
				st = t.nextToken();
			} catch (IOException e) {
				e.printStackTrace();
			}
			list.add(st);
		}
		return list;
	}

	// parse only assertions, ie. concept and role assertions
	public static Assertion parseAssertions(LinkedList<String> tokens,
			DescriptionLogicsKB kb) throws SyntaxParsingException {
		Assertion ast = null;
		if (tokens.peek() == null) {
			System.out.println("Empty list of tokens, please check!");
			throw new SyntaxParsingException();
		}
		String first = tokens.getFirst();
		if (!first.equals(LEFTDEL)) {
			System.out.println("Outer brackets expected.");
			throw new SyntaxParsingException();
		} else {
			tokens.remove();
			// remove the last symbol which is ")"
			String test = tokens.removeLast();
			assert test.equals(RIGHTDEL);
		}
		if (tokens.peek().equals(CONASSERT)) {
			tokens.remove();
			ast = Creator.createConceptAssertion(tokens, kb);
		} else if (tokens.peek().equals(ROLEASSERT)) {
			// equivalent axiom
			tokens.remove();
			ast = Creator.createRoleAssertion(tokens, kb);
		}
		return ast;
	}

	// public static AlgebraicOP parseAlgebraQuery(LinkedList<String> tokens)
	// throws SyntaxParsingException{
	// if(tokens.peek() == null){
	// System.out.println("Empty list of tokens, please check!");
	// throw new SyntaxParsingException();
	// }
	// AlgebraicOP query = null;
	// String first = tokens.getFirst();
	// if(first.equals(LEFTDEL)){
	// tokens.remove();
	// tokens.removeLast();
	// }
	// first = tokens.poll();
	// if(first.equals(QCON)){
	// query = new ConstantOP(conParser(tokens));
	// }else if(first.equals(QINFORM)){
	// LinkedList<LinkedList<String>> subs =
	// breakListByMatchingBrackets(tokens);
	// if(subs.size()!=2){
	// throw new SyntaxParsingException();
	// }else{
	// //C, Pd
	// query = new ObjectQuery(conParser(subs.get(0)),
	// createProjectionDescription(subs.get(1))).translateAsExpression();
	// }
	// }else if(first.equalsIgnoreCase(QPROJ)){
	// LinkedList<LinkedList<String>> subs =
	// breakListByMatchingBrackets(tokens);
	// if(subs.size()!=2){
	// throw new SyntaxParsingException();
	// }else{
	// //Q, Pd
	// query = new ProjectionOP( createProjectionDescription(subs.get(1)),
	// parseAlgebraQuery(subs.get(0)));
	// }
	// }else if(first.equalsIgnoreCase(QINTER)){
	// LinkedList<LinkedList<String>> subs =
	// breakListByMatchingBrackets(tokens);
	// if(subs.size()!=2){
	// throw new SyntaxParsingException();
	// }else{
	// query = new IntersectionOP( parseAlgebraQuery(subs.get(0)),
	// parseAlgebraQuery(subs.get(1)));
	// }
	// }else if(first.equalsIgnoreCase(QPI)){
	// query = new PrimaryOP(null);
	// }else if(first.equalsIgnoreCase(QSCAN)){
	// //sub-Q
	// LinkedList<LinkedList<String>> subs =
	// breakListByMatchingBrackets(tokens);
	// if(subs.size() != 1){
	// throw new SyntaxParsingException();
	// }else{
	// query = new ScanOP( parseAlgebraQuery(subs.get(0)), null);
	// }
	// }else if(first.equalsIgnoreCase(QSELECT)){
	// //C, Q
	// LinkedList<LinkedList<String>> subs =
	// breakListByMatchingBrackets(tokens);
	// if(subs.size()!=2){
	// throw new SyntaxParsingException();
	// }else{
	// query = new SelectionOP( parseAlgebraQuery(subs.get(1)),
	// conParser(subs.get(0)));
	// }
	// }else{
	// System.out.println("Query type not supported: "+ first);
	// throw new SyntaxParsingException();
	// }
	// return query;
	// }

	protected static String listToStringSpaced(LinkedList<String> tokens) {
		String s = "";
		while (!tokens.isEmpty()) {
			String cur = tokens.poll();
			if (cur.trim().length() < 1) {
				continue;
			}
			s += cur;
			String next = tokens.peek();
			if (!cur.equals("(") && (next == null || !next.equals(")"))) {
				s += " ";
			}
		}
		return s.trim();
	}

	public static String tokensAsString(LinkedList<String> in) {
		String ret = "";
		while (!in.isEmpty()) {
			ret += in.poll() + " ";
		}
		return ret.trim();
	}

	// divide the tokens into one or more subsets, each of which is of the form
	// "(aaa)" or "aaa".
	public static List<LinkedList<String>> breakListByMatchingBrackets(
			LinkedList<String> in) {
		List<LinkedList<String>> res = new LinkedList<LinkedList<String>>();
		if (in.peek() == null) {
			System.out.println("Empty list of tokens, please check!");
			throw new RuntimeException();
		}
		String tk = null;
		int count = 0;
		LinkedList<String> sub = new LinkedList<String>();
		while (!in.isEmpty()) {
			tk = in.poll();

			if (tk.equals(LEFTDEL)) {
				count++;
			} else if (tk.equals(RIGHTDEL)) {
				count--;
			}
			sub.add(tk);
			if (count == 0) {
				break;
			}
		}// end of while
		res.add(sub);
		if (in.size() > 0) {
			res.addAll(breakListByMatchingBrackets(in));
		}
		return res;
	}

	protected static void estimateSizeofCp(Concept c, KBStat stat) {
		Set<AtomicConcept> cs = c.extracAtomicConcepts();
		if (c instanceof NotConcept || c instanceof ExistsConcept
				|| c instanceof UniversalConcept) {
			return;
		}
		if (c instanceof OrConcept) {
			int value = 1 / cs.size();
			for (AtomicConcept ac : cs) {
				stat.setCpCounts(ac, value);
			}
		} else {
			for (AtomicConcept ac : cs) {
				// default value is 1.0
				stat.incCpCounts(ac);
			}
		}
		return;
	}

	// deal with concepts only
	public static Concept conParser(LinkedList<String> tokens, DescriptionLogicsKB kb)
			throws SyntaxParsingException {
		if (tokens.peek() == null) {
			throw new SyntaxParsingException(
					"Empty list of tokens, please check!");
		}
		Concept ret = null;
		// int counter = 0;
		// remove outer brackets if any
		if (tokens.peek().equals(LEFTDEL)) {
			tokens.remove();
			tokens.removeLast();
		}
		// cases
		String tk = tokens.getFirst();
		if (tk.equals(LEFTDEL)) {
			// counter ++;
			tokens.remove();
		} else if (tk.equals(RIGHTDEL)) {
			// counter --;
			tokens.remove();
		} else if (tk.equals(AND)) {
			tokens.remove();
			if (tokens.isEmpty()) {
				// we assume that (and) is top
				return CONCEPT_TOP;
			}
			ret = Creator.createAndConcept(tokens, kb);
		} else if (tk.equals(SOME)) {
			tokens.remove();
			ret = Creator.createExistsConcept(tokens, kb);
		} else if (tk.equals(ALL)) {
			tokens.remove();
			ret = Creator.createUniversalConcept(tokens, kb);
		} else if (tk.equals(OR)) {
			tokens.remove();
			if (tokens.isEmpty()) {
				// we assume that (and) is top
				return CONCEPT_BOTTOM;
			}
			ret = Creator.createOrConcept(tokens, kb);
		} else if (tk.equals(NOT)) {
			tokens.remove();
			ret = Creator.createNotConcept(tokens, kb);
		} else if (tk.equals(EQ)) {
			// concrete domains
			tokens.remove();
			ret = Creator.createDomainConcept(tokens, 0, kb);
		} else if (tk.equals(LESSTHAN)) {
			tokens.remove();
			ret = Creator.createDomainConcept(tokens, -1, kb);
		} else if (tk.equals(LESSEQUAL)) {
			tokens.remove();
			ret = Creator.createDomainConcept(tokens, 1, kb);
		} else if (tk.equals(NOMINAL)) {
			tokens.remove();
			ret = Creator.createNominalConcept(tokens, kb);
		}
		// if no keywords found, then this is a PC
		else {
			ret = Creator.createPConcept(tk);
			KBStat stat = null;
			if(kb!=null){
				stat = kb.getKBStat();
			}
			if (stat != null) {
				stat.incTotalConcepts();
				stat.addEntityNames(tk, "concept");
			}
		}
		return ret;
	}

}
